<?php

/**
 * 观察着模式
 *
 * 场景+观察者
 *
 * 实现方式：PHP标准库的 SplSubject + SplObserver
 *
 * 缺点：观察者通知实现是foreach循环执行，如果第一个通知异常，下面的通知也不能用了
 *
 */


/**
 * 观察场景类
 */
class Order implements SplSubject{
    private $observers;

    public function __construct()
    {
        $this->observers = new SplObjectStorage();
    }

    /**
     * 添加观察者
     *
     * @param
     * @return void
     */
    public function attach(SplObserver $observer)
    {
        // TODO: Implement attach() method.
        $this->observers->attach($observer);
    }

    /**
     * 删除观察者
     *
     * @param
     * @return void
     */
    public function detach(SplObserver $observer)
    {
        // TODO: Implement detach() method.
        $this->observers->detach($observer);
    }

    public function notify()
    {
        // TODO: Implement notify() method.
        foreach ($this->observers as $observer){
            $observer->update($this);
        }
    }
}

/**
 * 短信通知 观察者
 */
class SmsObserver implements SplObserver{
    public function update(SplSubject $subject)
    {
        // TODO: Implement update() method.
        echo get_class($subject)."短信通知成功".PHP_EOL;
    }
}

/**
 * 邮件通知 观察者
 */
class EmailObserver implements SplObserver{
    public function update(SplSubject $subject)
    {
        // TODO: Implement update() method.
        echo get_class($subject)."邮件通知成功".PHP_EOL;
    }
}

/**
 * 站内通知 观察者
 */
class MessageObserver implements SplObserver{
    public function update(SplSubject $subject)
    {
        // TODO: Implement update() method.
        echo get_class($subject)."站内通知成功".PHP_EOL;
    }
}

$orderObj = new Order();
$orderObj->attach(new SmsObserver());
$orderObj->attach(new EmailObserver());

//如果以后添加站内信通知只须实现SplObserver接口，然后在这里添加即可实现
$orderObj->attach(new MessageObserver());
$orderObj->notify();